package main

import (
    "fmt"
    "sort"
)

/*
    perform ->prepare->save->add
 */

type BindNamespace struct {
}

type Namespace struct {
    Name           string           `json:"name,omitempty"`
    NamespaceType  NamespaceType    `json:"type,omitempty"`
    Items          map[string]*Item `json:"items,omitempty"`
    actionHandlers []NamespaceActionHandler
}


func (ns *Namespace) findOrCreateItemByPath(p string) *Item  {
    if ns.Items == nil {
        ns.Items = make(map[string]*Item)
    }
    if _, ok := ns.Items[p]; !ok {
        ns.Items[p] = NewEmptyItem(p)
    }
    return ns.Items[p]
}

func (ns *Namespace) Hashcode() uint64 {
    var offsets Offsets
    for _, v := range ns.Items {
        offsets = append(offsets, v.Offset)
    }
    sort.Sort(offsets)
    var code uint64
    for _, o := range offsets {
        code = 31*code + o
    }
    return code
}
func (ns *Namespace) TypeName() string {
    return ns.NamespaceType.TypeName
}

//just basic steps
func (ns *Namespace) Add(action *Action) error {
    if action.Offset == 0 || action.Version == "" {
        return fmt.Errorf("action not prepared  ")
    }
    if action.Namespace != ns.Name {
        return fmt.Errorf("action namespace: %s not match with namespace: %s", action.Namespace, ns.Name)
    }
    item  := ns.findOrCreateItemByPath(action.Path)
    if action.Version == "" {
        action.Version = DefaultVersion
    }
    for _, h := range ns.actionHandlers {
        if err := h.OnAdd(action, item); err != nil {
            return err
        }
    }
    return nil
}

//just basic steps
//prepare -> save action -> add -> save offset
func (ns *Namespace) Prepare(action *Action) error {
    if action.Version == "" { //reset version info
        action.Version = DefaultVersion
    }
    if action.Path == "" {
        return fmt.Errorf("empty path in action")
    }
    if action.ActionType < 0 || action.ActionType > DropRelation {
        return fmt.Errorf("wrong action type in action")
    }
    if action.Namespace != ns.Name {
        return fmt.Errorf("action namespace: %s not match with namespace: %s", action.Namespace, ns.Name)
    }
    for k := range action.Properties {
        if k == KEY_NAMESPACE || k == KEY_PATH || k == KEY_ACTION_TYPE ||
            k == KEY_VERSION || k == KEY_OFFSET || k == KEY_CREATE_TIME {
            return fmt.Errorf("property key:%s contains reserved words", k)
        }
    }
    item  := ns.findOrCreateItemByPath(action.Path)
    for _, h := range ns.actionHandlers {
        if err := h.OnPrepare(action, item); err != nil {
            return err
        }
    }
    return nil
}
